﻿using System;
using System.Collections.Generic;
using System.Text;

namespace MLForgeSharp.Models.UnsupervisedLearningModels.Clustering
{
    /// <summary>
    /// 模糊C均值聚类
    /// </summary>
    public class FuzzyCMeansModel
    {
        private double[][] data; // 数据集
        private int c; // 簇的数量
        private double m; // 模糊指数
        private int maxIterations; // 最大迭代次数
        private double[,] membershipMatrix; // 隶属度矩阵
        private double[][] centroids; // 簇中心

        public FuzzyCMeansModel(int c = 2, double m = 2.0, int maxIterations = 100)
        {
            this.c = c;
            this.m = m;
            this.maxIterations = maxIterations;
        }

        // 计算欧氏距离
        private double EuclideanDistance(double[] a, double[] b)
        {
            double sum = 0.0;
            for (int i = 0; i < a.Length; i++)
            {
                sum += Math.Pow(a[i] - b[i], 2);
            }
            return Math.Sqrt(sum);
        }

        // 初始化隶属度矩阵
        private void InitializeMembershipMatrix()
        {
            int numSamples = data.Length;
            membershipMatrix = new double[numSamples, c];
            Random rand = new Random();

            for (int i = 0; i < numSamples; i++)
            {
                double sum = 0.0;
                for (int j = 0; j < c; j++)
                {
                    membershipMatrix[i, j] = rand.NextDouble();
                    sum += membershipMatrix[i, j];
                }

                // 归一化
                for (int j = 0; j < c; j++)
                {
                    membershipMatrix[i, j] /= sum;
                }
            }
        }

        // 更新簇中心
        private void UpdateCentroids()
        {
            int numSamples = data.Length;
            int numFeatures = data[0].Length;
            centroids = new double[c][];

            for (int j = 0; j < c; j++)
            {
                centroids[j] = new double[numFeatures];
                double sumMembership = 0.0;

                for (int i = 0; i < numSamples; i++)
                {
                    double membership = Math.Pow(membershipMatrix[i, j], m);
                    for (int k = 0; k < numFeatures; k++)
                    {
                        centroids[j][k] += membership * data[i][k];
                    }
                    sumMembership += membership;
                }

                for (int k = 0; k < numFeatures; k++)
                {
                    centroids[j][k] /= sumMembership;
                }
            }
        }

        // 更新隶属度矩阵
        private void UpdateMembershipMatrix()
        {
            int numSamples = data.Length;

            for (int i = 0; i < numSamples; i++)
            {
                for (int j = 0; j < c; j++)
                {
                    double sum = 0.0;
                    for (int k = 0; k < c; k++)
                    {
                        double distanceToJ = EuclideanDistance(data[i], centroids[j]);
                        double distanceToK = EuclideanDistance(data[i], centroids[k]);
                        sum += Math.Pow(distanceToJ / distanceToK, 2.0 / (m - 1));
                    }
                    membershipMatrix[i, j] = 1.0 / sum;
                }
            }
        }

        // 训练模型
        public void Train(double[][] data)
        {
            this.data = data;
            InitializeMembershipMatrix();

            for (int iter = 0; iter < maxIterations; iter++)
            {
                UpdateCentroids();
                double[,] oldMembershipMatrix = (double[,])membershipMatrix.Clone();
                UpdateMembershipMatrix();

                // 检查是否收敛
                bool converged = true;
                for (int i = 0; i < data.Length; i++)
                {
                    for (int j = 0; j < c; j++)
                    {
                        if (Math.Abs(membershipMatrix[i, j] - oldMembershipMatrix[i, j]) > 1e-6)
                        {
                            converged = false;
                            break;
                        }
                    }
                    if (!converged)
                    {
                        break;
                    }
                }

                if (converged)
                {
                    break;
                }
            }
        }

        // 获取隶属度矩阵
        public double[,] GetMembershipMatrix()
        {
            return membershipMatrix;
        }

        // 获取簇中心
        public double[][] GetCentroids()
        {
            return centroids;
        }
    }

    // 示例程序
    public class FuzzyCMeansModelExample
    {
        public FuzzyCMeansModelExample()
        {
            // 示例数据
            double[][] data = new double[][]
        {
            new double[] { 1.0, 2.0 },
            new double[] { 1.1, 2.1 },
            new double[] { 1.2, 2.2 },
            new double[] { 10.0, 10.0 },
            new double[] { 10.1, 10.1 },
            new double[] { 10.2, 10.2 }
        };

            // 创建模型
            FuzzyCMeansModel model = new FuzzyCMeansModel(c: 2, m: 2.0, maxIterations: 100);

            // 训练模型
            model.Train(data);

            // 获取隶属度矩阵
            double[,] membershipMatrix = model.GetMembershipMatrix();

            // 获取簇中心
            double[][] centroids = model.GetCentroids();

            // 打印隶属度矩阵
            System.Console.WriteLine("隶属度矩阵:");
            for (int i = 0; i < data.Length; i++)
            {
                for (int j = 0; j < 2; j++)
                {
                    System.Console.Write(membershipMatrix[i, j].ToString("F4") + " ");
                }
                System.Console.WriteLine();
            }

            // 打印簇中心
            System.Console.WriteLine("簇中心:");
            for (int i = 0; i < centroids.Length; i++)
            {
                System.Console.WriteLine("簇 " + i + ": (" + centroids[i][0] + ", " + centroids[i][1] + ")");
            }
        }
    }
}
